1
2
3
4
5
6 package ch.twiddlefinger.inet.rewinder.model.parser.conversion;
7
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.io.OutputStream;
11 import java.lang.reflect.Array;
12 import java.lang.reflect.Constructor;
13 import java.nio.ByteBuffer;
14 import java.nio.ByteOrder;
15
16 /***
17 * <p> This class represents a <code>C/C++ struct</code>; it confers
18 * interoperability between Java classes and C/C++ struct.</p>
19 * <p> Unlike <code>C/C++</code>, the storage layout of Java objects is not
20 * determined by the compiler. The layout of objects in memory is deferred
21 * to run time and determined by the interpreter (or just-in-time compiler).
22 * This approach allows for dynamic loading and binding; but also makes
23 * interfacing with <code>C/C++</code> code difficult. Hence, this class for
24 * which the memory layout is defined by the initialization order of the
25 * {@link Struct}'s {@link Member members} and follows the same alignment
26 * rules as <code>C/C++ structs</code>.</p>
27 * <p> This class (as well as the {@link Union} sub-class) facilitates:
28 * <ul>
29 * <li> Memory sharing between Java applications and native libraries.</li>
30 * <li> Direct encoding/decoding of streams for which the structure
31 * is defined by legacy C/C++ code.</li>
32 * <li> Serialization/deserialization of Java objects (complete control,
33 * e.g. no class header)</li>
34 * <li> Mapping of Java objects to physical addresses (with JNI).</li>
35 * </ul></p>
36 * <p> Because of its one-to-one mapping, it is relatively easy to convert C
37 * header files (e.g. OpenGL bindings) to Java {@link Struct}/{@link Union}
38 * using simple text macros. Here is an example of C struct:<pre>
39 * struct Date {
40 * unsigned short year;
41 * unsigned char month;
42 * unsigned char day;
43 * };
44 * struct Student {
45 * char name[64];
46 * struct Date birth;
47 * float grades[10];
48 * Student* next;
49 * };</pre>
50 * and here is the Java equivalent using this class:<pre>
51 * public static class Date extends Struct {
52 * public final Unsigned16 year = new Unsigned16();
53 * public final Unsigned8 month = new Unsigned8();
54 * public final Unsigned8 day = new Unsigned8();
55 * }
56 * public static class Student extends Struct {
57 * public final UTF8String name = new UTF8String(64);
58 * public final Date birth = (Date) new StructMember(Date.class).get();
59 * public final Float32[] grades = (Float32[]) new ArrayMember(Float32.class, 10).get();
60 * public final Reference32 next = new Reference32(Student.class);
61 * }</pre>
62 * Struct's members are directly accessible:<pre>
63 * Student student = new Student();
64 * student.name.set("John Doe"); // Null terminated (C compatible)
65 * int age = 2003 - student.birth.year.get();
66 * student.grades[2].set(12.5f);
67 * student = (Student) student.next.get();</pre></p>
68 * <p> Applications may also work with the raw {@link #byteBuffer() bytes}
69 * directly:<pre>
70 * Struct message = new Message();
71 * SocketChannel socket = SocketChannel.open(address);
72 * // Reads message.
73 * message.byteBuffer().position(0);
74 * socket.read(message.byteBuffer());
75 * // Writes message.
76 * message.byteBuffer().position(0);
77 * socket.write(message.byteBuffer());</pre>
78 * {@link Struct} can be used to read UDP packets directly:<pre>
79 * class MyUdpMessage extends Struct {
80 * ... // UDP message fields.
81 * public MyUdpMessage(byte[] bytes) {
82 * super(ByteBuffer.wrap(bytes));
83 * }
84 * }
85 * public void run() {
86 * byte[] bytes = new byte[1024];
87 * DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
88 * MyUdpMessage message = new MyUdpMessage(bytes);
89 * // packet and message are now different views of the same data.
90 * while (true) {
91 * _socket.receive(packet);
92 * ... // Process message fields.
93 * packet.setLength(bytes.length); // Reset length to buffer's length.
94 * }
95 * }</pre></p>
96 * <p> It is relatively easy to map instances of this class to any physical
97 * address using
98 * <a href="http://java.sun.com/docs/books/tutorial/native1.1/index.html">
99 * JNI</a>. Here is an example:<pre>
100 * import java.nio.ByteBuffer;
101 * class Clock extends Struct { // Hardware clock mapped to memory.
102 * Unsigned16 seconds = new Unsigned16(5); // unsigned short seconds:5
103 * Unsigned16 minutes = new Unsigned16(5); // unsigned short minutes:5
104 * Unsigned16 hours = new Unsigned16(4); // unsigned short hours:4
105 * Clock() {
106 * super(Clock.nativeBuffer());
107 * }
108 * private static native ByteBuffer nativeBuffer();
109 * }</pre>
110 * Below is the <code>nativeBuffer()</code> implementation
111 * (<code>Clock.c</code>):<pre>
112 * #include <jni.h>
113 * #include "Clock.h" // Generated using javah
114 * JNIEXPORT jobject JNICALL Java_Clock_nativeBuffer (JNIEnv *env, jclass) {
115 * return (*env)->NewDirectByteBuffer(env, clock_address, buffer_size)
116 * }</pre></p>
117 * <p> Finally, bit-fields are supported (see <code>Clock</code> example above).
118 * Bit-fields allocation order is defined by the {@link Struct}'s
119 * {@link #byteOrder byte order} (leftmost bit to rightmost bit if
120 * <code>BIG_ENDIAN</code> and rightmost bit to leftmost bit if
121 * <code>LITTLE_ENDIAN</code>).
122 * Bit-fields cannot straddle the storage-unit boundary as defined by their
123 * base type (padding is inserted at the end of the first bit-field
124 * and the second bit-field is put into the next storage unit).</p>
125 *
126 * <p><i> This class is <b>public domain</b> (not copyrighted).</i></p>
127 *
128 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
129 * @version 5.3, December 7, 2003
130 */
131 public abstract class Struct {
132
133 /***
134 * Holds the current outer struct during construction process.
135 */
136 private static final ThreadLocal OUTER = new ThreadLocal();
137
138 /***
139 * Holds the byte buffer backing the struct.
140 */
141 private ByteBuffer _byteBuffer;
142
143 /***
144 * Holds the number of bits currently used (for size calculation).
145 */
146 private int _bitsUsed;
147
148 /***
149 * Holds this struct alignment (largest alignment of its members).
150 */
151 private int _alignment;
152
153 /***
154 * Holds the current bit index position (during construction).
155 */
156 private int _bitIndex;
157
158 /***
159 * Indicates if the index has to be reset for each new field.
160 */
161 private boolean _resetIndex;
162
163 /***
164 * Holds the outer struct if any.
165 */
166 private final Struct _outer;
167
168 /***
169 * Holds the offset in the outer struct buffer.
170 */
171 private int _outerOffset;
172
173 /***
174 * Default constructor. Top-level {@link Struct} created using this
175 * constructor are backed by a direct buffer. Inner {@link Struct} are
176 * always backed by the buffer of their outer parent.
177 */
178 public Struct() {
179 this(null);
180 }
181
182 /***
183 * Creates a {@link Struct} backed by the specified {@link ByteBuffer}.
184 * This constructor allows for the use of direct buffers mapped
185 * to memory. The address of the first field is always at position
186 * <code>0</code> in the specified buffer.
187 *
188 * @param byteBuffer the byte buffer for this {@link Struct}.
189 */
190 public Struct(ByteBuffer byteBuffer) {
191 _resetIndex = (this instanceof Union);
192 _byteBuffer = byteBuffer;
193 _outer = (Struct)OUTER.get();
194 }
195
196 /***
197 * Returns the size in bytes of this {@link Struct}. The size includes
198 * tail padding to satisfy the {@link Struct} alignment requirement
199 * (defined by the largest alignment of its {@link Member members}).
200 *
201 * @return the C/C++ <code>sizeof(this)</code>.
202 */
203 public final int size() {
204 int nbrOfBytes = (_bitsUsed + 7) >> 3;
205 return ((nbrOfBytes % _alignment) == 0) ? nbrOfBytes :
206 nbrOfBytes + _alignment - (nbrOfBytes % _alignment);
207 }
208
209 /***
210 * Returns the {@link ByteBuffer} backing this {@link Struct}.
211 *
212 * <p> Changes to the buffer's content are visible in the {@link Struct},
213 * and vice versa.</p>
214 * <p> The buffer limit is {@link #size()} and its position index is
215 * undefined. Methods modifying the buffer position should either
216 * synchronize on the buffer or work with a duplicate.</p>
217 * <p> The buffer of an inner {@link Struct} is a shared subsequence of
218 * the buffer's content of its outer parent.
219 * <p> The buffer is direct if, and only if, this {@link Struct}
220 * (or its outer {@link Struct}) is backed by a direct buffer (see
221 * {@link #Struct(ByteBuffer)}).</p>
222 * <p> The position index of a {@link Struct.Member} within the buffer is
223 * given by {@link Struct.Member#offset} (the first field member
224 * starting at <code>0</code>).</p>
225 *
226 * @return the actual byte buffer for this {@link Struct}.
227 */
228 public final ByteBuffer byteBuffer() {
229 return (_byteBuffer != null) ? _byteBuffer : newBuffer();
230 }
231
232 private synchronized ByteBuffer newBuffer() {
233 if (_byteBuffer == null) {
234 int size = size();
235 if (_outer == null) {
236 int capacity = isPacked() ?
237
238 ((( size & 0x7)==0) ? size : size + 8 - ( size & 0x7)) :
239 size;
240 _byteBuffer = ByteBuffer.allocateDirect(capacity);
241 _byteBuffer.order(byteOrder());
242 } else {
243 ByteBuffer outerBuffer = _outer.byteBuffer();
244 synchronized (outerBuffer) {
245 outerBuffer.position(_outerOffset);
246 ByteBuffer subBuffer = outerBuffer.slice();
247
248 _byteBuffer = subBuffer;
249 }
250 _byteBuffer.order(_outer.byteOrder());
251 }
252 }
253 return _byteBuffer;
254 }
255
256 /***
257 * Copies the content of the specified source {@link Struct} to the
258 * specified destination {@link Struct}.
259 *
260 * @param src the source {@link Struct}.
261 * @param dest the destination {@link Struct}.
262 * @return <code>dest</code>
263 * @throws IllegalArgumentException if <code>dest</code> is not an instance
264 * of <code>src.getClass()</code>,
265 */
266 public static Struct copy(Struct src, Struct dest) {
267 if (src.getClass().isInstance(dest)) {
268 ByteBuffer srcBuffer = src.byteBuffer();
269 ByteBuffer destBuffer = dest.byteBuffer();
270 synchronized (srcBuffer) {
271 synchronized (destBuffer) {
272 srcBuffer.position(0);
273 destBuffer.position(0);
274 srcBuffer.put(destBuffer);
275 }
276 }
277 return dest;
278 } else {
279 throw new IllegalArgumentException("Instance of " + src.getClass() +
280 " expected, found instance of " + dest.getClass());
281 }
282 }
283
284 /***
285 * Indicates if this {@link Struct} is equal to the specified object.
286 *
287 * @param that the object to compare for equality.
288 * @return <code>true</code> if this struct and the specified object are
289 * both struct of same class with same content;
290 * <code>false</code> otherwise.
291 */
292 public boolean equals(Object that) {
293 if (this.getClass() == that.getClass()) {
294 ByteBuffer thisBuffer = this.byteBuffer();
295 ByteBuffer thatBuffer = ((Struct)that).byteBuffer();
296 synchronized (thisBuffer) {
297 synchronized (thatBuffer) {
298 thisBuffer.position(0);
299 thatBuffer.position(0);
300 return thisBuffer.equals(thatBuffer);
301 }
302 }
303 } else {
304 return false;
305 }
306 }
307
308 /***
309 * Returns a hash code value for this {@link Struct}.
310 *
311 * <p> Note: Because {@link Struct} hash codes are content-dependent,
312 * it is inadvisable to use {@link Struct} as keys in hash maps
313 * or similar data structures unless it is known that their
314 * contents will not change.</p>
315 *
316 * @return this struct hash code value.
317 */
318 public final int hashCode() {
319 ByteBuffer thisBuffer = this.byteBuffer();
320 synchronized (thisBuffer) {
321 thisBuffer.position(0);
322 return thisBuffer.hashCode();
323 }
324 }
325
326 /***
327 * Returns this {@link Struct} address. This method allows for
328 * {@link Struct} to be referenced (e.g. pointer) from other {@link Struct}.
329 *
330 * @return the struct memory address.
331 * @throws UnsupportedOperationException if the struct's buffer is not
332 * a direct buffer.
333 */
334 public final long address() {
335 ByteBuffer thisBuffer = this.byteBuffer();
336 if (thisBuffer instanceof sun.nio.ch.DirectBuffer) {
337 return ((sun.nio.ch.DirectBuffer)thisBuffer).address();
338 } else {
339 throw new UnsupportedOperationException(
340 "Operation not supported for " + thisBuffer.getClass());
341 }
342 }
343
344 /***
345 * Returns the <code>String</code> representation of this {@link Struct}
346 * in the form of its constituing bytes (hexadecimal). For example:<pre>
347 * public static class Student extends Struct {
348 * UTF8String name = new UTF8String(16);
349 * Unsigned16 year = new Unsigned16();
350 * Float32 grade = new Float32();
351 * }
352 * Student student = new Student();
353 * student.name.set("John Doe");
354 * student.year.set(2003);
355 * student.grade.set(12.5f);
356 * System.out.println(student);
357 *
358 * 4a 6f 68 6e 20 44 6f 65 00 00 00 00 00 00 00 00
359 * 07 d3 00 00 41 48 00 00</pre>
360 *
361 * @return a hexadecimal representation of the bytes content for this
362 * {@link Struct}.
363 */
364 public final String toString() {
365 StringBuffer stringBuffer = new StringBuffer(3 * size());
366 final int size = size();
367 final ByteBuffer buffer = byteBuffer();
368 for (int i = 0; i < size; i++) {
369 int b = buffer.get(i) & 0xFF;
370 if (b < 0x10) {
371
372 stringBuffer.append('0');
373 }
374 TypeFormat.format(b, 16, stringBuffer);
375 if ((i & 0xF) == 0xF) {
376
377 stringBuffer.append('\n');
378 } else {
379 stringBuffer.append(' ');
380 }
381 }
382 return stringBuffer.toString();
383 }
384
385
386
387
388
389 /***
390 * Returns the byte order for this {@link Struct}. The byte order is
391 * inherited by inner structs. Sub-classes may change the byte order
392 * by overriding this method. For example:<pre>
393 * public final class TopStruct {
394 * ... // Members initialization.
395 * public ByteOrder byteOrder() {
396 * // TopStruct and its inner structs use hardware byte order.
397 * return ByteOrder.nativeOrder();
398 * }
399 * }}</pre></p></p>
400 *
401 * @return the byte order when reading/writing multibyte values
402 * (default: network byte order, <code>BIG_ENDIAN</code>).
403 */
404 public ByteOrder byteOrder() {
405 if (_outer != null) {
406 return _outer.byteOrder();
407 } else {
408 return ByteOrder.BIG_ENDIAN;
409 }
410 }
411
412 /***
413 * Indicates if this {@link Struct} is packed.
414 * By default, {@link Member} of a {@link Struct} are aligned on the
415 * boundary corresponding to the member's base type; padding is performed
416 * if necessary. This directive is inherited by inner structs.
417 * Sub-classes may change the packing directive by overriding this method.
418 * For example:<pre>
419 * public final class TopStruct {
420 * ... // Members initialization.
421 * public boolean isPacked() {
422 * // TopStruct and its inner structs are packed.
423 * return true;
424 * }
425 * }}</pre></p></p>
426 *
427 * @return <code>true</code> if alignment requirements are ignored.
428 * <code>false</code> otherwise (default).
429 */
430 public boolean isPacked() {
431 if (_outer != null) {
432 return _outer.isPacked();
433 } else {
434 return false;
435 }
436 }
437
438
439
440
441
442 /***
443 * This inner class represents the base class for all {@link Struct}
444 * members. It allows applications to define additional member types.
445 * For example:<pre>
446 * public class MyStruct extends Struct {
447 * BitSet bits = new BitSet(256);
448 * ...
449 * public BitSet extends Member {
450 * public BitSet(int nbrBits) {
451 * super(1, (nbrBits+7)>>3);
452 * }
453 * public boolean get(int i) { ... }
454 * public void set(int i, boolean value) { ...}
455 * }
456 * }</pre>
457 */
458 protected abstract class Member {
459
460 /***
461 * Holds the offset of this field in the struct's buffer.
462 */
463 private int _offset;
464
465 /***
466 * Default constructor (used internally for inner struct and bit-fields).
467 */
468 Member() {}
469
470 /***
471 * Base constructor for custom member types.
472 *
473 * @param alignment the desired alignment in bytes.
474 * @param size the size of this member in bytes.
475 */
476 protected Member(int alignment, int size) {
477 final int nbrOfBits = size << 3;
478 updateIndexes(alignment, nbrOfBits, nbrOfBits);
479 }
480
481 /***
482 * Returns the offset of this {@link Struct.Member} in the
483 * {@link Struct}'s {@link Struct#byteBuffer() byte buffer}.
484 *
485 * @return the offset in bytes.
486 */
487 public final int offset() {
488 return _offset;
489 }
490
491 /***
492 * Updates the {@link Struct}'s indexes and size.
493 *
494 * @param alignment the desired alignment in bytes.
495 * @param nbrOfBits the size in bits.
496 * @param capacity the word size maximum capacity in bits
497 * (equal to nbrOfBits for non-bitfields).
498 * @throws IllegalArgumentException if
499 * <code>nbrOfBits > capacity</code>
500 */
501 void updateIndexes(int alignment, int nbrOfBits, int capacity) {
502 if (nbrOfBits > capacity) {
503 throw new IllegalArgumentException("nbrOfBits: " + nbrOfBits +
504 " exceeds capacity: " + capacity);
505 }
506
507
508 if (_resetIndex) {
509 _bitIndex = 0;
510 }
511
512
513 alignment = isPacked() ? 1 : alignment;
514 _offset = (_bitIndex / (alignment << 3)) * alignment;
515 int usedBits = _bitIndex - (_offset << 3);
516
517
518 if ((capacity < usedBits + nbrOfBits) || (nbrOfBits == 0)) {
519
520 _offset += alignment;
521 _bitIndex = (_offset << 3) + nbrOfBits;
522 } else {
523 _bitIndex += nbrOfBits;
524 }
525
526
527 if (_bitsUsed < _bitIndex) {
528 _bitsUsed = _bitIndex;
529 }
530
531
532 if (Struct.this._alignment < alignment) {
533 Struct.this._alignment = alignment;
534 }
535 }
536
537 /***
538 * Creates a new instance of specified type.
539 *
540 * @param classType the class type.
541 * @return an object of the specified class type created using its
542 * default constructor.
543 * @throws ClassCastException if classType is not derived from
544 * {@link Struct} or from {@link Struct.Member}.
545 */
546 Object newInstance(Class classType) {
547 try {
548 if (Member.class.isAssignableFrom(classType)) {
549
550 Constructor[] constructors = classType.getConstructors();
551 for (int i=0; i < constructors.length; i++) {
552 Class[] params= constructors[i].getParameterTypes();
553 if ( (params.length == 1) &&
554 Struct.class.isAssignableFrom(params[0]) ) {
555 return constructors[i].newInstance(
556 new Object[] {Struct.this});
557 }
558 }
559 throw new NoSuchMethodError(
560 classType + " has no public default constructor");
561 }
562
563 Struct outer = (Struct)OUTER.get();
564 OUTER.set(Struct.this);
565 Struct struct = (Struct)classType.newInstance();
566 OUTER.set(outer);
567 final int bitSize = struct.size() << 3;
568 updateIndexes(struct._alignment, bitSize, bitSize);
569 struct._outerOffset = (_bitIndex - bitSize) >> 3;
570 return struct;
571
572
573 } catch (InstantiationException e1) {
574 throw new InstantiationError(e1.getMessage());
575 } catch (IllegalAccessException e2) {
576 throw new IllegalAccessError(e2.getMessage());
577 } catch (java.lang.reflect.InvocationTargetException e3) {
578 throw new Error(e3.getMessage());
579 }
580 }
581 }
582
583 /***
584 * This class represents an inner struct member.
585 */
586 public final class StructMember extends Member {
587
588 /***
589 * Holds the inner struct.
590 */
591 private final Struct _struct;
592
593 /***
594 * Creates a {@link Struct.StructMember} having an inner struct
595 * of specified type.
596 *
597 * @param structType the class of the inner struct.
598 * @throws ClassCastException if the specified class is not derived from
599 * {@link Struct}.
600 */
601 public StructMember(Class structType) {
602 _struct = (Struct)newInstance(structType);
603 }
604
605 /***
606 * Returns the struct represented by this {@link Struct.StructMember}.
607 *
608 * @return the inner struct.
609 */
610 public Struct get() {
611 return _struct;
612 }
613 }
614
615 /***
616 * This class represents an array member. Array's element can be
617 * {@link Struct.Member} or {@link Struct}/{@link Union}. For example the
618 * following C code:<pre>
619 * struct Vertex {
620 * float x;
621 * float y;
622 * };
623 * struct Rectangle {
624 * int colors[4];
625 * struct Vertex vertices[2][2];
626 * char text[4][20];
627 * };</pre>
628 * would be represented by:<pre>
629 * public class Vertex extends Struct {
630 * public final Float32 x = new Float32();
631 * public final Float32 y = new Float32();
632 * }
633 * public class Rectangle extends Struct {
634 * public final Signed32[] colors = (Signed32[]) new ArrayMember(Signed32.class, 4).get();
635 * public final Vertex[][] vertices = (Vertex[][]) new ArrayMember(Vertex.class, new int[] {2, 2}).get();
636 * public final UTF8String20[] text = (UTF8String20[]) new ArrayMember(UTF8String20.class, 4).get();
637 * public class UTF8String20 extends UTF8String {
638 * public UTF8String20() { // Default constructor (no argument) to be used.
639 * super(20); // UTF8String of 20 bytes.
640 * }
641 * }
642 * }</pre>
643 * Arrays elements are directly accessible:<pre>
644 * float x01 = myRectangle.vertices[0][1].x.get();
645 * myRectangle.colors[2].set(0xFF00FF);
646 * myRectangle.text[0].set("Blah, Blah, Blah");</pre>
647 */
648 public final class ArrayMember extends Member {
649
650 /***
651 * Holds the array.
652 */
653 private final Object _array;
654
655 /***
656 * Creates an {@link Struct.ArrayMember} of specified component type.
657 *
658 * @param componentType the component type of the array.
659 * @param length the length of the array.
660 * @throws ClassCastException if the componentType is not derived
661 * from {@link Struct.Member} or {@link Struct}.
662 */
663 public ArrayMember(Class componentType, int length) {
664 this(componentType, new int[] {length});
665 }
666
667 /***
668 * Creates an {@link Struct.ArrayMember} of specified component type and
669 * dimensions.
670 *
671 * @param componentType the component type of the array.
672 * @param dimensions the dimensions of the array.
673 * @throws ClassCastException if the componentType is not derived
674 * from {@link Struct.Member} or {@link Struct}.
675 */
676 public ArrayMember(Class componentType, int[] dimensions) {
677 if (_resetIndex) {
678 _bitIndex = 0;
679 _resetIndex = false;
680 _array = newArray(componentType, dimensions);
681 _resetIndex = true;
682 } else {
683 _array = newArray(componentType, dimensions);
684 }
685 }
686
687 private Object newArray(Class componentType, int[] dimensions) {
688 Object array = Array.newInstance(componentType, dimensions);
689 int length = dimensions[0];
690 if (dimensions.length == 1) {
691 for (int i = 0; i < length; i++) {
692 Object obj = newInstance(componentType);
693 Array.set(array, i, obj);
694 }
695 } else {
696 final int[] innerDim = new int[dimensions.length - 1];
697 for (int i = 1; i < dimensions.length; i++) {
698 innerDim[i - 1] = dimensions[i];
699 }
700 for (int i = 0; i < length; i++) {
701 Array.set(array, i, newArray(componentType, innerDim));
702 }
703 }
704 return array;
705 }
706
707 /***
708 * Returns the array represented by this {@link Struct.ArrayMember}.
709 *
710 * @return the array member.
711 */
712 public Object get() {
713 return _array;
714 }
715 }
716
717
718
719
720
721 /***
722 * This class represents a UTF-8 character string, null terminated
723 * (for C/C++ compatibility)
724 */
725 public class UTF8String extends Member {
726 private final Utf8StreamWriter _writer;
727 private final Utf8StreamReader _reader;
728 private final char[] _charBuffer;
729
730 public UTF8String(int length) {
731 super(1, length);
732 final int indexLast = offset() + length;
733 _writer = new Utf8StreamWriter(length);
734 _writer.setOutputStream(new OutputStream() {
735 public void write(int b) throws IOException {
736 final ByteBuffer buffer = byteBuffer();
737 if (buffer.position() < indexLast) {
738 buffer.put((byte)b);
739 }
740 }
741 });
742 _reader = new Utf8StreamReader(length);
743 _reader.setInputStream(new InputStream() {
744 public int read() throws IOException {
745 final ByteBuffer buffer = byteBuffer();
746 if (buffer.position() < indexLast) {
747 byte b = buffer.get();
748 if (b != 0) {
749 return b;
750 }
751 }
752 return -1;
753 }
754 });
755 _charBuffer = new char[length];
756 }
757
758 public void set(String string) {
759 final ByteBuffer buffer = byteBuffer();
760 synchronized (buffer) {
761 try {
762 buffer.position(offset());
763 _writer.write(string);
764 _writer.write(0);
765 _writer.flush();
766 } catch (IOException e) {
767 throw new Error(e);
768 }
769 }
770 }
771
772 public String get() {
773 final ByteBuffer buffer = byteBuffer();
774 synchronized (buffer) {
775 try {
776 buffer.position(offset());
777 int length = _reader.read(_charBuffer);
778 return (length > 0) ? new String(_charBuffer, 0,
779 length) : "";
780 } catch (IOException e) {
781 throw new Error(e);
782 }
783 }
784 }
785 }
786
787 /***
788 * This class represents a 8 bits boolean with <code>true</code> represented
789 * by <code>1</code> and <code>false</code> represented by <code>0</code>.
790 */
791 public class Bool extends Member {
792 private final int _mask;
793 private final int _shift;
794 public Bool() {
795 this(8);
796 }
797
798 public Bool(int nbrOfBits) {
799 updateIndexes(1, nbrOfBits, 8);
800 final int startBit = offset() << 3;
801 _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
802 8 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
803 _mask = ((1 << nbrOfBits) - 1) << _shift;
804 }
805
806 public boolean get() {
807 return (byteBuffer().get(offset()) & _mask) != 0;
808 }
809
810 public void set(boolean value) {
811 if (_mask == 0xFF) {
812 byteBuffer().put(offset(), (byte) (value ? 1 : 0));
813 } else {
814 int prevCleared = byteBuffer().get(offset()) & (~_mask);
815 if (value) {
816 byteBuffer().put(
817 offset(), (byte) (prevCleared | (1 << _shift)));
818 } else {
819 byteBuffer().put(offset(), (byte) (prevCleared));
820 }
821 }
822 }
823 }
824
825 /***
826 * This class represents a 8 bits signed integer.
827 */
828 public class Signed8 extends Member {
829 private final int _mask;
830 private final int _shift;
831 private final int _signShift;
832 public Signed8() {
833 this(8);
834 }
835 public Signed8(int nbrOfBits) {
836 updateIndexes(1, nbrOfBits, 8);
837 final int startBit = offset() << 3;
838 _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
839 8 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
840 _mask = ((1 << nbrOfBits) - 1) << _shift;
841 _signShift = 32 - _shift - nbrOfBits;
842 }
843
844 public byte get() {
845 if (_mask == 0xFF) {
846 return byteBuffer().get(offset());
847 } else {
848 int value = byteBuffer().get(offset());
849 value &= _mask;
850 value <<= _signShift;
851 value >>= _signShift + _shift;
852 return (byte)value;
853 }
854 }
855
856 public void set(byte value) {
857 if (_mask == 0xFF) {
858 byteBuffer().put(offset(), value);
859 } else {
860 value <<= _shift;
861 value &= _mask;
862 int orMask = byteBuffer().get(offset()) & (~_mask);
863 byteBuffer().put(offset(), (byte)(orMask | value));
864 }
865 }
866 }
867
868 /***
869 * This class represents a 8 bits unsigned integer.
870 */
871 public class Unsigned8 extends Member {
872 private final int _shift;
873 private final int _mask;
874 public Unsigned8() {
875 this(8);
876 }
877
878 public Unsigned8(int nbrOfBits) {
879 updateIndexes(1, nbrOfBits, 8);
880 final int startBit = offset() << 3;
881 _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
882 8 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
883 _mask = ((1 << nbrOfBits) - 1) << _shift;
884 }
885
886 public short get() {
887 int value = byteBuffer().get(offset());
888 return (short)((value & _mask) >>> _shift);
889 }
890
891 public void set(short value) {
892 if (_mask == 0xFF) {
893 byteBuffer().put(offset(), (byte)value);
894 } else {
895 value <<= _shift;
896 value &= _mask;
897 int orMask = byteBuffer().get(offset()) & (~_mask);
898 byteBuffer().put(offset(), (byte)(orMask | value));
899 }
900 }
901 }
902
903 /***
904 * This class represents a 16 bits signed integer.
905 */
906 public class Signed16 extends Member {
907 private final int _mask;
908 private final int _shift;
909 private final int _signShift;
910 public Signed16() {
911 this(16);
912 }
913
914 public Signed16(int nbrOfBits) {
915 updateIndexes(2, nbrOfBits, 16);
916 final int startBit = offset() << 3;
917 _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
918 16 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
919 _mask = ((1 << nbrOfBits) - 1) << _shift;
920 _signShift = 32 - _shift - nbrOfBits;
921 }
922
923 public short get() {
924 if (_mask == 0xFFFF) {
925 return byteBuffer().getShort(offset());
926 } else {
927 int value = byteBuffer().getShort(offset());
928 value &= _mask;
929 value <<= _signShift;
930 value >>= _signShift + _shift;
931 return (short)value;
932 }
933 }
934
935 public void set(short value) {
936 if (_mask == 0xFFFF) {
937 byteBuffer().putShort(offset(), value);
938 } else {
939 value <<= _shift;
940 value &= _mask;
941 int orMask = byteBuffer().getShort(offset()) & (~_mask);
942 byteBuffer().putShort(offset(), (short)(orMask | value));
943 }
944 }
945 }
946
947 /***
948 * This class represents a 16 bits unsigned integer.
949 */
950 public class Unsigned16 extends Member {
951 private final int _shift;
952 private final int _mask;
953 public Unsigned16() {
954 this(16);
955 }
956
957 public Unsigned16(int nbrOfBits) {
958 updateIndexes(2, nbrOfBits, 16);
959 final int startBit = offset() << 3;
960 _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
961 16 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
962 _mask = ((1 << nbrOfBits) - 1) << _shift;
963 }
964
965 public int get() {
966 int value = byteBuffer().getShort(offset());
967 return (value & _mask) >>> _shift;
968 }
969
970 public void set(int value) {
971 if (_mask == 0xFFFF) {
972 byteBuffer().putShort(offset(), (short)value);
973 } else {
974 value <<= _shift;
975 value &= _mask;
976 int orMask = byteBuffer().getShort(offset()) & (~_mask);
977 byteBuffer().putShort(offset(), (short)(orMask | value));
978 }
979 }
980 }
981
982 /***
983 * This class represents a 32 bits signed integer.
984 */
985 public class Signed32 extends Member {
986 private final int _mask;
987 private final int _shift;
988 private final int _signShift;
989 public Signed32() {
990 this(32);
991 }
992
993 public Signed32(int nbrOfBits) {
994 updateIndexes(4, nbrOfBits, 32);
995 final int startBit = offset() << 3;
996 _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
997 32 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
998 _mask = (nbrOfBits == 32) ? 0xFFFFFFFF :
999 ((1 << nbrOfBits) - 1) << _shift;
1000 _signShift = 32 - _shift - nbrOfBits;
1001 }
1002
1003 public int get() {
1004 if (_mask == 0xFFFFFFFF) {
1005 return byteBuffer().getInt(offset());
1006 } else {
1007 int value = byteBuffer().getInt(offset());
1008 value &= _mask;
1009 value <<= _signShift;
1010 value >>= _signShift + _shift;
1011 return value;
1012 }
1013 }
1014
1015 public void set(int value) {
1016 if (_mask == 0xFFFFFFFF) {
1017 byteBuffer().putInt(offset(), value);
1018 } else {
1019 value <<= _shift;
1020 value &= _mask;
1021 int orMask = byteBuffer().getInt(offset()) & (~_mask);
1022 byteBuffer().putInt(offset(), orMask | value);
1023 }
1024 }
1025 }
1026
1027 /***
1028 * This class represents a 32 bits unsigned integer.
1029 */
1030 public class Unsigned32 extends Member {
1031 private final int _shift;
1032 private final long _mask;
1033 public Unsigned32() {
1034 this(32);
1035 }
1036
1037 public Unsigned32(int nbrOfBits) {
1038 updateIndexes(4, nbrOfBits, 32);
1039 final int startBit = offset() << 3;
1040 _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
1041 32 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
1042 _mask = (nbrOfBits == 32) ? 0xFFFFFFFFl :
1043 ((1l << nbrOfBits) - 1l) << _shift;
1044 }
1045
1046 public long get() {
1047 int value = byteBuffer().getInt(offset());
1048 return (value & _mask) >>> _shift;
1049 }
1050
1051 public void set(long value) {
1052 if (_mask == 0xFFFFFFFF) {
1053 byteBuffer().putInt(offset(), (int)value);
1054 } else {
1055 value <<= _shift;
1056 value &= _mask;
1057 int orMask = byteBuffer().getInt(offset()) & (~(int)_mask);
1058 byteBuffer().putInt(offset(), (int)(orMask | value));
1059 }
1060 }
1061 }
1062
1063 /***
1064 * This class represents a 64 bits signed integer.
1065 */
1066 public class Signed64 extends Member {
1067 private final long _mask;
1068 private final int _shift;
1069 private final int _signShift;
1070 public Signed64() {
1071 this(64);
1072 }
1073
1074 public Signed64(int nbrOfBits) {
1075 updateIndexes(8, nbrOfBits, 64);
1076 final int startBit = offset() << 3;
1077 _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
1078 64 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
1079 _mask = (nbrOfBits == 64) ? 0xFFFFFFFFFFFFFFFFl :
1080 ((1l << nbrOfBits) - 1l) << _shift;
1081 _signShift = 64 - _shift - nbrOfBits;
1082 }
1083
1084 public long get() {
1085 if (_mask == 0xFFFFFFFFFFFFFFFFl) {
1086 return byteBuffer().getLong(offset());
1087 } else {
1088 long value = byteBuffer().getLong(offset());
1089 value &= _mask;
1090 value <<= _signShift;
1091 value >>= _signShift + _shift;
1092 return value;
1093 }
1094 }
1095
1096 public void set(long value) {
1097 if (_mask == 0xFFFFFFFFFFFFFFFFl) {
1098 byteBuffer().putLong(offset(), value);
1099 } else {
1100 value <<= _shift;
1101 value &= _mask;
1102 long orMask = byteBuffer().getLong(offset()) & (~_mask);
1103 byteBuffer().putLong(offset(), orMask | value);
1104 }
1105 }
1106 }
1107
1108 /***
1109 * This class represents a 32 bits float (C/C++/Java <code>float</code>).
1110 */
1111 public class Float32 extends Member {
1112 public Float32() {
1113 super(4, 4);
1114 }
1115
1116 public void set(float value) {
1117 byteBuffer().putFloat(offset(), value);
1118 }
1119
1120 public float get() {
1121 return byteBuffer().getFloat(offset());
1122 }
1123 }
1124
1125 /***
1126 * This class represents a 64 bits float (C/C++/Java <code>double</code>).
1127 */
1128 public class Float64 extends Member {
1129 public Float64() {
1130 super(8, 8);
1131 }
1132
1133 public void set(double value) {
1134 byteBuffer().putDouble(offset(), value);
1135 }
1136
1137 public double get() {
1138 return byteBuffer().getDouble(offset());
1139 }
1140 }
1141
1142 /***
1143 * <p> This class represents a 32 bits reference (C/C++ pointer) to
1144 * a {@link Struct} object (other types may require a {@link Struct}
1145 * wrapper).</p>
1146 * <p> Note: For references which can be externally modified, an application
1147 * may want to check the {@link #isUpToDate up-to-date} status of
1148 * the reference. For out-of-date references, a new {@link Struct}
1149 * can be created at the address specified by {@link #value}
1150 * (using JNI) and then {@link #set set} to the reference.</p>
1151 */
1152 public class Reference32 extends Member {
1153 private final Class _structClass;
1154 private Struct _struct;
1155 public Reference32(Class structClass) {
1156 super(4, 4);
1157 if (Struct.class.isAssignableFrom(structClass)) {
1158 _structClass = structClass;
1159 } else {
1160 throw new IllegalArgumentException(
1161 structClass + " is not a Struct/Union");
1162 }
1163 }
1164
1165 public void set(Struct struct) {
1166 if (_structClass.isInstance(struct)) {
1167 byteBuffer().putInt(offset(), (int) struct.address());
1168 } else if (struct == null) {
1169 byteBuffer().putInt(offset(), 0);
1170 } else {
1171 throw new IllegalArgumentException(
1172 "struct: Is an instance of " + struct.getClass() +
1173 ", instance of " + _structClass + " expected");
1174 }
1175 _struct = struct;
1176 }
1177 public Struct get() {
1178 return _struct;
1179 }
1180 public int value() {
1181 return byteBuffer().getInt(offset());
1182 }
1183 public boolean isUpToDate() {
1184 if (_struct != null) {
1185 return byteBuffer().getInt(offset()) == (int)_struct.address();
1186 } else {
1187 return byteBuffer().getInt(offset()) == 0;
1188 }
1189 }
1190 }
1191
1192 /***
1193 * <p> This class represents a 64 bits reference (C/C++ pointer) to
1194 * a {@link Struct} object (other types may require a {@link Struct}
1195 * wrapper).</p>
1196 * <p> Note: For references which can be externally modified, an application
1197 * may want to check the {@link #isUpToDate up-to-date} status of
1198 * the reference. For out-of-date references, a new {@link Struct}
1199 * can be created at the address specified by {@link #value}
1200 * (using JNI) and then {@link #set set} to the reference.</p>
1201 */
1202 public class Reference64 extends Member {
1203 private final Class _structClass;
1204 private Struct _struct;
1205 public Reference64(Class structClass) {
1206 super(8, 8);
1207 if (Struct.class.isAssignableFrom(structClass)) {
1208 _structClass = structClass;
1209 } else {
1210 throw new IllegalArgumentException(
1211 structClass + " is not a Struct/Union");
1212 }
1213 }
1214
1215 public void set(Struct struct) {
1216 if (_structClass.isInstance(struct)) {
1217 byteBuffer().putLong(offset(), struct.address());
1218 } else if (struct == null) {
1219 byteBuffer().putLong(offset(), 0L);
1220 } else {
1221 throw new IllegalArgumentException(
1222 "struct: Is an instance of " + struct.getClass() +
1223 ", instance of " + _structClass + " expected");
1224 }
1225 _struct = struct;
1226 }
1227 public Struct get() {
1228 return _struct;
1229 }
1230 public long value() {
1231 return byteBuffer().getLong(offset());
1232 }
1233 public boolean isUpToDate() {
1234 if (_struct != null) {
1235 return byteBuffer().getLong(offset()) == _struct.address();
1236 } else {
1237 return byteBuffer().getLong(offset()) == 0L;
1238 }
1239 }
1240 }
1241
1242 /***
1243 * This class represents a 8 bits {@link Enum}.
1244 */
1245 public class Enum8 extends Member {
1246 private final int _mask;
1247 private final int _shift;
1248 private final int _signShift;
1249 private final Class _enumClass;
1250 public Enum8(Class enumClass) {
1251 this(enumClass, 8);
1252 }
1253
1254 public Enum8(Class enumClass, int nbrOfBits) {
1255 _enumClass = enumClass;
1256 updateIndexes(1, nbrOfBits, 8);
1257 final int startBit = offset() << 3;
1258 _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
1259 8 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
1260 _mask = ((1 << nbrOfBits) - 1) << _shift;
1261 _signShift = 32 - _shift - nbrOfBits;
1262 }
1263
1264 public Enum get() {
1265 if (_mask == 0xFF) {
1266 return Enum.valueOf(byteBuffer().get(offset()), _enumClass);
1267 } else {
1268 int value = byteBuffer().get(offset());
1269 value &= _mask;
1270 value <<= _signShift;
1271 value >>= _signShift + _shift;
1272 return Enum.valueOf(value, _enumClass);
1273 }
1274 }
1275
1276 public void set(Enum enum) {
1277 if (!_enumClass.isInstance(enum)) {
1278 throw new IllegalArgumentException(
1279 "enum: " + enum + " is not instance of " + _enumClass);
1280 }
1281 byte value = enum.byteValue();
1282 if (_mask == 0xFF) {
1283 byteBuffer().put(offset(), value);
1284 } else {
1285 value <<= _shift;
1286 value &= _mask;
1287 int orMask = byteBuffer().get(offset()) & (~_mask);
1288 byteBuffer().put(offset(), (byte)(orMask | value));
1289 }
1290 }
1291 }
1292
1293 /***
1294 * This class represents a 16 bits {@link Enum}.
1295 */
1296 public class Enum16 extends Member {
1297 private final int _mask;
1298 private final int _shift;
1299 private final int _signShift;
1300 private final Class _enumClass;
1301 public Enum16(Class enumClass) {
1302 this(enumClass, 16);
1303 }
1304
1305 public Enum16(Class enumClass, int nbrOfBits) {
1306 _enumClass = enumClass;
1307 updateIndexes(2, nbrOfBits, 16);
1308 final int startBit = offset() << 3;
1309 _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
1310 16 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
1311 _mask = ((1 << nbrOfBits) - 1) << _shift;
1312 _signShift = 32 - _shift - nbrOfBits;
1313 }
1314
1315 public Enum get() {
1316 if (_mask == 0xFFFF) {
1317 return Enum.valueOf(byteBuffer().getShort(offset()), _enumClass);
1318 } else {
1319 int value = byteBuffer().getShort(offset());
1320 value &= _mask;
1321 value <<= _signShift;
1322 value >>= _signShift + _shift;
1323 return Enum.valueOf(value, _enumClass);
1324 }
1325 }
1326
1327 public void set(Enum enum) {
1328 if (!_enumClass.isInstance(enum)) {
1329 throw new IllegalArgumentException(
1330 "enum: " + enum + " is not instance of " + _enumClass);
1331 }
1332 short value = enum.shortValue();
1333 if (_mask == 0xFFFF) {
1334 byteBuffer().putShort(offset(), value);
1335 } else {
1336 value <<= _shift;
1337 value &= _mask;
1338 int orMask = byteBuffer().getShort(offset()) & (~_mask);
1339 byteBuffer().putShort(offset(), (short)(orMask | value));
1340 }
1341 }
1342 }
1343
1344 /***
1345 * This class represents a 32 bits {@link Enum}.
1346 */
1347 public class Enum32 extends Member {
1348 private final int _mask;
1349 private final int _shift;
1350 private final int _signShift;
1351 private final Class _enumClass;
1352 public Enum32(Class enumClass) {
1353 this(enumClass, 32);
1354 }
1355
1356 public Enum32(Class enumClass, int nbrOfBits) {
1357 _enumClass = enumClass;
1358 updateIndexes(4, nbrOfBits, 32);
1359 final int startBit = offset() << 3;
1360 _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
1361 32 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
1362 _mask = (nbrOfBits == 32) ? 0xFFFFFFFF :
1363 ((1 << nbrOfBits) - 1) << _shift;
1364 _signShift = 32 - _shift - nbrOfBits;
1365 }
1366
1367 public Enum get() {
1368 if (_mask == 0xFFFFFFFF) {
1369 return Enum.valueOf(byteBuffer().getInt(offset()), _enumClass);
1370 } else {
1371 int value = byteBuffer().getInt(offset());
1372 value &= _mask;
1373 value <<= _signShift;
1374 value >>= _signShift + _shift;
1375 return Enum.valueOf(value, _enumClass);
1376 }
1377 }
1378
1379 public void set(Enum enum) {
1380 if (!_enumClass.isInstance(enum)) {
1381 throw new IllegalArgumentException(
1382 "enum: " + enum + " is not instance of " + _enumClass);
1383 }
1384 int value = enum.intValue();
1385 if (_mask == 0xFFFFFFFF) {
1386 byteBuffer().putInt(offset(), value);
1387 } else {
1388 value <<= _shift;
1389 value &= _mask;
1390 int orMask = byteBuffer().getInt(offset()) & (~_mask);
1391 byteBuffer().putInt(offset(), orMask | value);
1392 }
1393 }
1394 }
1395 /***
1396 * This class represents a 64 bits {@link Enum}.
1397 */
1398 public class Enum64 extends Member {
1399 private final long _mask;
1400 private final int _shift;
1401 private final int _signShift;
1402 private final Class _enumClass;
1403 public Enum64(Class enumClass) {
1404 this(enumClass, 64);
1405 }
1406 public Enum64(Class enumClass, int nbrOfBits) {
1407 _enumClass = enumClass;
1408 updateIndexes(8, nbrOfBits, 64);
1409 final int startBit = offset() << 3;
1410 _shift = (byteOrder() == ByteOrder.BIG_ENDIAN) ?
1411 64 - _bitIndex + startBit : _bitIndex - startBit - nbrOfBits;
1412 _mask = (nbrOfBits == 64) ? 0xFFFFFFFFFFFFFFFFl :
1413 ((1l << nbrOfBits) - 1l) << _shift;
1414 _signShift = 64 - _shift - nbrOfBits;
1415 }
1416
1417 public Enum get() {
1418 if (_mask == 0xFFFFFFFFFFFFFFFFl) {
1419 return Enum.valueOf(byteBuffer().getLong(offset()), _enumClass);
1420 } else {
1421 long value = byteBuffer().getLong(offset());
1422 value &= _mask;
1423 value <<= _signShift;
1424 value >>= _signShift + _shift;
1425 return Enum.valueOf(value, _enumClass);
1426 }
1427 }
1428
1429 public void set(Enum enum) {
1430 if (!_enumClass.isInstance(enum)) {
1431 throw new IllegalArgumentException(
1432 "enum: " + enum + " is not instance of " + _enumClass);
1433 }
1434 long value = enum.longValue();
1435 if (_mask == 0xFFFFFFFFFFFFFFFFl) {
1436 byteBuffer().putLong(offset(), value);
1437 } else {
1438 value <<= _shift;
1439 value &= _mask;
1440 long orMask = byteBuffer().getLong(offset()) & (~_mask);
1441 byteBuffer().putLong(offset(), orMask | value);
1442 }
1443 }
1444 }
1445 }